%{
#include <stdio.h>
#include <stdlib.h>
#include "lp_defs.h"
#include "../core/nodes/identifierstring.h"
#include "../core/nodes/list.h"
#include "../core/nodes/classnode.h"
#include "../core/nodes/classtype.h"
#include "../core/nodes/inheritancenode.h"
#include "../core/nodes/constant.h"
#include "../core/nodes/entity.h"
#include "../core/nodes/operators.h"
#include "../core/nodes/manifest_array.h"
#include "../core/nodes/calls.h"
#include "../core/nodes/conversion.h"
#include "../core/nodes/loops.h"
#include "recovery.h"
#define YY_LTYPE_IS_TRIVIAL

std::vector<ListNode<ClassNode> *> rootlist;
const char * current_filename=NULL;  //!< Current parsed filename

#ifdef _MSC_VER
	#pragma warning( disable : 4065 )
#endif

%}

%debug

%union {
  std::string                   *   m_strg;         //!< String data
  long long                         m_intl;         //!< Integral data
  double                            m_real;         //!< Real data
  char                              m_char;         //!< Character
  bool                              m_bool;         //!< Boolean		
  AbstractNode                  *   m_abstract;     //!< Node data
  ListNode<ClassNode>           *   m_cnlist;       //!< Class node list
  ListNode<FeatureGroup>        *   m_fglist;       //!< Feature group list
  ClassNode                     *   m_classnode;    //!< One class node
  ListNode<ConverterNode>       *   m_convlist;     //!< Converter list
  ListNode<CreatorNode>         *   m_crterlist;    //!< Creator list
  ListNode<InheritanceNode>     *   m_inherlist;    //!< Inheritance list
  ListNode<IdentifierNode>      *   m_idlist;       //!< Identifier list
  ClassTypeNode                 *   m_cltnode;      //!< Class type node
  InheritanceNode               *   m_inhernode;    //!< Inheritance node
  RenameNode                    *   m_rename;       //!< Rename node
  ListNode<RenameNode>          *   m_renlist;      //!< Rename list
  CreatorNode                   *   m_creator;      //!< Creator node
  ConverterNode                 *   m_converter;    //!< Converter node
  ListNode<ClassTypeNode>       *   m_cltlist;      //!< Class type list
  FeatureGroup                  *   m_featgroup;    //!< Feature group
  FeatureDeclaration            *   m_featdecl;     //!< Feature declaration
  ListNode<FeatureDeclaration>  *   m_featdlist;    //!< Feature declaration list
  EntityList                    *   m_entlist;      //!< Entity list
  EntityGroup                   *   m_entgroup;     //!< Entity group
  Constant                      *   m_constant;     //!< Constant
  ListNode<FeatureSpecName>     *   m_featslist;    //!< Feature spec list  
  Compound                      *   m_compound;     //!< Compound
  FromLoopNode                  *   m_loop;         //!< From loop node
  ManifestArray                 *   m_manarray;     //!< Manifest array
  CreationCall                  *   m_creatcall;    //!< Creation call
}


%token<m_strg>   END_OF_FILE 0 
%token<m_strg>	 INSTRUCTION_DELIMITER END_DECL CLASS DEFERRED FROZEN FEATURE 
%token<m_strg>   CONVERT TWO_DOTS GEQ LEQ TWO_SLASHES TWO_BACKSLASHES NOT AND OR XOR 
%token<m_strg>   AND_THEN OR_ELSE IMPLIES INHERIT RENAME AS DO LOCAL THEN 
%token<m_strg>   ELSE REDEFINE UNDEFINE CREATE SELECT IF INSPECT WHEN
%token<m_strg>   FROM UNTIL LOOP NEQ NTILDA ASSIGNMENT LEFT_ARRAY RIGHT_ARRAY ELSEIF ALIAS

%token<m_bool>   _BOOL 327
%token<m_intl>	 INTEGER 261
%token<m_real>	 REAL 262
%token<m_strg>	 STRING_LITERAL 263
%token<m_strg>	 _CHAR 264
%token<m_strg>   IDENTIFIER
  

%type<m_abstract>   main_list new_line_list nloe instruction_delimiter explicit_value
%type<m_cnlist>     class_list
%type<m_classnode>  class_declaration 
%type<m_fglist>     feature_group_list feature_group_list_oe
%type<m_convlist>   converter_clauses converter_list
%type<m_crterlist>  creator_list creator_list_oe
%type<m_inherlist>  inheritance_list inheritance_clauses
%type<m_classnode>  class_header basic_class_header
%type<m_idlist>     identifier_list   redefines
%type<m_cltnode>    class_type return_type creation_modifier
%type<m_inhernode>  inheritance_data  inheritance_basic inheritance_clause
%type<m_rename>     inheritance_rename
%type<m_renlist>    inheritance_rename_list renames
%type<m_creator>    creator
%type<m_converter>  converter
%type<m_cltlist>    class_type_list
%type<m_featgroup>  feature_group
%type<m_featdlist>  feature_declaration_list
%type<m_featdecl>   feature_declaration basic_feature_declaration
%type<m_entlist>    formal_arguments entity_list local_variables
%type<m_entgroup>   entity_group
%type<m_constant>   num_constant basic_constant constant  
%type<m_featslist>  feature_names
%type<m_compound>   compound     expression_list call_arguments
%type<m_abstract>   instruction  expression logic_expr logic_first logic_second 
%type<m_abstract>   compare addition power multiply unary_operator arr_access parenthesis
%type<m_abstract>   assignment basic_expression conversion invert
%type<m_loop>       basic_loop
%type<m_manarray>   manifest_array
%type<m_creatcall>  creation_call
%type<m_strg>       init_spec alias_feature_spec

%left  '.'
%left  '@'
%left  '['
%%

main_list: nloe END_OF_FILE                   {                         }
           | nloe class_list  END_OF_FILE     { rootlist.push_back($2); }

nloe:     /* empty */    {}
          |  new_line_list  {}
          ;

new_line_list: INSTRUCTION_DELIMITER            {  }
          | new_line_list INSTRUCTION_DELIMITER {  }
          ;
class_list:  class_declaration                { $$=CREATE_LIST(@1,ClassNode); $$->add($1); }
          |  class_list  class_declaration    { $$=$1; $$->add($2); }
          ;
          
class_declaration: class_header inheritance_clauses creator_list_oe converter_clauses  feature_group_list_oe END_DECL  nloe  { 
                                                                      $$=$1; 
                                                                      $$->features()=$5;
                                                                      $$->converters()=$4;
                                                                      $$->creators()=$3;
                                                                      $$->inherits()=$2; 
                                                                     }

feature_group_list_oe:  /* empty */         { $$=NULL; }
                      | feature_group_list  { $$=$1;   }
                      ;
feature_group_list: feature_group                    { $$=CREATE_LIST(@1,FeatureGroup); $$->add($1);  } 
               |   feature_group_list feature_group  { $$=$1; $$->add($2);}
               ;
converter_clauses:  /* empty */                  { $$=NULL; }
               |    CONVERT nloe converter_list  { $$=$3; $$->setLocation(@1);}
               ;
creator_list_oe: /* empty */  {$$=NULL;}
             |   creator_list {$$=$1;}
             ;
creator_list: creator                 { $$=CREATE_LIST(@1,CreatorNode); $$->add($1); }
         |    creator_list creator    { $$=$1; $$->add($2);}
         ;

inheritance_clauses:  /* empty */      { $$=NULL; }
               |     inheritance_list  { $$=$1;}
               ;
inheritance_list: inheritance_clause                   { $$=CREATE_LIST(@1,InheritanceNode); $$->add($1); }
              |   inheritance_list inheritance_clause  { $$=$1; $$->add($2);}
              ;
    
class_header: basic_class_header  { $$=$1; }
           |  DEFERRED nloe basic_class_header { ($$=$3)->setType(CLM_DEFERRED); $3->setLocation(@1); }
           |  FROZEN   nloe basic_class_header { ($$=$3)->setType(CLM_FROZEN);   $3->setLocation(@1); }
		   ;
basic_class_header: CLASS nloe IDENTIFIER nloe  { $$=new ClassNode(@1,$3); }

inheritance_clause: inheritance_basic renames redefines   {
                                                           $$=$1;
                                                           $$->setRedefines($3);
                                                           $$->setRenames($2);
                                                          }
redefines:  /* empty */  { $$=NULL; }
    |       REDEFINE nloe identifier_list {  $$=$3; $3->setLocation(@1); }
    ;
renames:    /* empty */  { $$=NULL; }
    |       RENAME nloe inheritance_rename_list { $$=$3; $3->setLocation(@1); }
    ;                  
inheritance_basic: INHERIT  nloe inheritance_data  { $$=$3; $$->setLocation(@1); }

inheritance_data:  class_type  {$$=new InheritanceNode($1); }

class_type:  IDENTIFIER nloe                                    { $$=new ClassTypeNode(@1,$1); }
           | IDENTIFIER nloe  '[' nloe identifier_list ']' nloe { $$=new ClassTypeNode(@1,$1); $$->setArgs($5); }
           ;


identifier_list:  IDENTIFIER  nloe                             { $$=CREATE_LIST(@1,IdentifierNode); $$->add(new IdentifierNode(@1,$1)); }
               |  identifier_list ',' nloe IDENTIFIER nloe     { $$=$1; $$->add(new IdentifierNode(@4,$4)); }
               ;

inheritance_rename_list: inheritance_rename                                   { $$=CREATE_LIST(@1,RenameNode);$$->add($1); }
                      | inheritance_rename_list ',' nloe  inheritance_rename  { $$=$1; $$->add($4); }
                      ;
inheritance_rename: IDENTIFIER nloe AS  nloe IDENTIFIER nloe                        { $$=new RenameNode(@1,$1,$5,NULL); }
                |   IDENTIFIER nloe AS  nloe IDENTIFIER nloe ALIAS STRING_LITERAL nloe    { $$=new RenameNode(@1,$1,$5,$8); }
                ; 
               
creator:  CREATE  nloe '{' nloe  identifier_list  '}' nloe  identifier_list  { $$=new CreatorNode(@1,$5,$8); }
       |  CREATE  nloe identifier_list                                       { $$=new CreatorNode(@1,NULL,$3); }
       ;
       
converter_list:  converter                         { $$=CREATE_LIST(@1,ConverterNode); $$->add($1); }
               | converter_list ',' nloe converter { $$=$1; $$->add($4); }  
               ;

class_type_list: class_type                                    { $$=CREATE_LIST(@1,ClassTypeNode); $$->add($1); }
               | class_type_list ',' nloe class_type           { $$=$1; $$->add($4); } 
               ;

converter: IDENTIFIER  nloe '(' nloe '{' nloe class_type_list '}' nloe ')' nloe   { $$=new ConverterNode(@1,$1,$7,CT_PROCEDURE ); }
        |  IDENTIFIER  nloe ':' nloe '{' nloe class_type_list '}' nloe            { $$=new ConverterNode(@1,$1,$7,CT_QUERY ); }
        ;

feature_group:  FEATURE nloe '{' nloe identifier_list '}' nloe feature_declaration_list { $$=new FeatureGroup(@1,$5,$8);}
             |  FEATURE nloe feature_declaration_list                                   { $$=new FeatureGroup(@1,NULL,$3);}
             ;
feature_declaration_list: feature_declaration                          { $$=CREATE_LIST(@1,FeatureDeclaration); $$->add($1); }
                     |    feature_declaration_list feature_declaration { $$=$1; $$->add($2); }
                     ;

feature_declaration: basic_feature_declaration                                              { $$=$1;                           }
                  |  basic_feature_declaration explicit_value                               { $$=$1; $1->setExplicitValue($2); }
                  |  basic_feature_declaration DEFERRED nloe END_DECL nloe                  { $$=$1; $1->makeDeferredMethod(); }
                  |  basic_feature_declaration local_variables DO  compound END_DECL nloe   { $$=$1; $1->makeEffective($2,$4); }
                  |  feature_names  DEFERRED nloe END_DECL nloe                             { $$=new FeatureDeclaration(@1,$1,NULL);  $$->makeDeferredMethod();  } 
                  |  feature_names  local_variables DO  compound END_DECL nloe              { $$=new FeatureDeclaration(@1,$1,NULL);  $$->makeEffective($2,$4);  }
                  |  feature_names formal_arguments return_type DEFERRED nloe END_DECL nloe                 { $$=new FeatureDeclaration(@1,$1,$2,$3); }
                  |  feature_names formal_arguments return_type local_variables DO  compound END_DECL nloe  { $$=new FeatureDeclaration(@1,$1,$2,$3,$4,$6);}
                  ;                     

basic_feature_declaration: feature_names ':' nloe class_type                                                      { $$=new FeatureDeclaration(@1,$1,$4);    }

explicit_value: '=' constant nloe                              { $$=$2; $2->setLocation(@1);       }
           |    '=' '{' nloe class_type '}' nloe constant nloe { $$=new ConversionNode(@1,$4,$7);  }
           ;

constant: '-' num_constant  { $$=$2; $2->negate(@1); }
        | num_constant      { $$=$1;               }
        | basic_constant    { $$=$1;               }
        ;
basic_constant: _BOOL          { $$=new Constant(@1,$1); }
              | _CHAR          { $$=new Constant(@1,true,$1); }
              | STRING_LITERAL { $$=new Constant(@1,false,$1); }

num_constant: REAL      { $$=new Constant(@1,$1); }
              | INTEGER { $$=new Constant(@1,$1); }
              ;

feature_names: IDENTIFIER nloe  alias_feature_spec                                     { $$=add( CREATE_LIST(@1,FeatureSpecName),@1, FDT_NONE, $1,$3);}
        |      FROZEN nloe IDENTIFIER nloe     alias_feature_spec                      { $$=add( CREATE_LIST(@1,FeatureSpecName),@1, FDT_FROZEN, $3,$5);}
        |      feature_names ',' nloe IDENTIFIER nloe alias_feature_spec               { $$=add($1,@4,FDT_NONE,$4,$6);  }
        |      feature_names ',' nloe FROZEN nloe IDENTIFIER nloe alias_feature_spec   { $$=add($1,@4,FDT_FROZEN,$6,$8);}
        ;

alias_feature_spec: /*empty*/               { $$=NULL;}
                  | ALIAS nloe STRING_LITERAL nloe  { $$=$3;}
                  ;
                  
formal_arguments: '(' nloe ')' nloe             { $$=CREATE_LIST(@1,EntityGroup); }  
                | '(' nloe entity_list ')' nloe { $$=$3; $3->setLocation(@1); }
                ;

return_type:     /* empty */             { $$=NULL; }
          |      ':' nloe class_type     { $$=$3; }
          ;
          
local_variables: /* empty */             { $$=NULL; } 
          |      LOCAL nloe entity_list  { $$=$3; }
          ;

entity_list: entity_group                       { $$=CREATE_LIST(@1,EntityGroup); $$->add($1); }
          |  entity_group  ';' nloe             { $$=CREATE_LIST(@1,EntityGroup); $$->add($1); }
          |  entity_list entity_group           { $$=$1; $$->add($2); }
          |  entity_list entity_group  ';' nloe { $$=$1; $$->add($2); }
          ;

entity_group: identifier_list ':' nloe  class_type    { $$=new EntityGroup($1,$4);}


compound: instruction                                     { $$=CREATE_LIST(@1,AbstractNode); $$->add($1); }
       |  compound instruction_delimiter instruction      { $$=$1;                           $$->add($3); }
       ;

expression_list: expression nloe                      { $$=CREATE_LIST(@1,AbstractNode); $$->add($1); }
               | expression_list ',' expression nloe  { $$=$1;                           $$->add($3); }
               ;

instruction_delimiter: INSTRUCTION_DELIMITER { $$=NULL; } 
                  |    ';'                   { $$=NULL; }
                  

instruction:  /* empty */   { $$=NULL; } 
           |  assignment    { $$=$1;   }
           |  creation_call { $$=$1;   }
           |  basic_loop    { $$=$1;   } 
           |  arr_access   { $$=$1;   }
		   ;
		   
assignment:  arr_access ASSIGNMENT expression  { $$=new OperatorNode(@2,$1,$3,":="); }

                             
expression:  logic_expr      { $$=$1; }
         |    manifest_array { $$=$1; }
		 ;
		 
manifest_array: LEFT_ARRAY nloe expression_list RIGHT_ARRAY  {$$=new ManifestArray(@1,$3); }

logic_expr:  logic_expr OR logic_second  { $$=new OperatorNode(@2,$1,$3,"or");}
          |  logic_expr XOR logic_second { $$=new OperatorNode(@2,$1,$3,"xor");}
          |  logic_second  {$$=$1; }
          ;


logic_second:  logic_second AND logic_first { $$=new OperatorNode(@2,$1,$3,"and");}
          |    logic_first  {$$=$1;}
          ;

logic_first:  logic_first IMPLIES compare {  $$=new OperatorNode(@2,$1,$3,"implies");}
		   | logic_first  AND_THEN compare {  $$=new OperatorNode(@2,$1,$3,"and then");}
           | logic_first  OR_ELSE compare {   $$=new OperatorNode(@2,$1,$3,"or else");}
           | compare {$$=$1;}
           ;

compare: compare  '=' addition    { $$=new OperatorNode(@2,$1,$3,"="); }
       | compare  '~' addition    { $$=new OperatorNode(@2,$1,$3,"~"); }
       | compare  NTILDA addition { $$=new OperatorNode(@2,$1,$3,"/~");}
       | compare  NEQ addition    { $$=new OperatorNode(@2,$1,$3,"/=");}
       | compare  GEQ addition    { $$=new OperatorNode(@2,$1,$3,">=");}
       | compare  LEQ addition    { $$=new OperatorNode(@2,$1,$3,"<=");}
       | compare  '<' addition    { $$=new OperatorNode(@2,$1,$3,"<"); }
       | compare  '>' addition    { $$=new OperatorNode(@2,$1,$3,">"); }
       | addition  { $$=$1; }
       ;
       
addition:  addition  '+' multiply  {$$=new OperatorNode(@2,$1,$3,"+");}
       |   addition  '-' multiply  {$$=new OperatorNode(@2,$1,$3,"-");}
       |  multiply  { $$=$1; }
       ;

multiply: multiply  '*' power           { $$=new OperatorNode(@2,$1,$3,"*");}
	|  multiply  '/' power              { $$=new OperatorNode(@2,$1,$3,"/");}
    |  multiply  TWO_BACKSLASHES power  { $$=new OperatorNode(@2,$1,$3,"\\\\");}
    |  multiply  TWO_SLASHES power      { $$=new OperatorNode(@2,$1,$3,"//");}
    |  power {$$=$1; }
    ;
power:  power '^' unary_operator { $$=new OperatorNode(@2,$1,$3,"^"); }
    |   unary_operator           { $$=$1; }
    ;
unary_operator:     arr_access        { $$=$1; }
			|       NOT arr_access    { $$=new OperatorNode(@1,$2,"not");}
			; 

arr_access:  conversion                                  { $$=$1; }
	      |  arr_access '[' expression ']' 	             { $$=new OperatorNode(@2,$1,$3,"[]");}
          |  arr_access '@' basic_expression             { $$=new OperatorNode(@2,$1,$3,"[]");}
          |  arr_access '.' IDENTIFIER  call_arguments   { $$=new AttributeAccess(@1,$1,$3,$4); }
          ;

conversion:  invert                       { $$=$1; } 
         | '{' class_type '}' conversion  { $$=new ConversionNode(@1,$2,$4);}

invert: basic_expression           { $$=$1;             }
     | '-' basic_expression        { $$=$2->negate(@1); }
     ;

basic_expression: num_constant     { $$=$1; }
				| basic_constant   { $$=$1; }
				| IDENTIFIER       { $$=new IdentifierNode(@1,$1);}
                | parenthesis      { $$=$1; }
                ;
                
parenthesis: '(' expression ')' { $$=$2; $2->setLocation(@1); }

creation_call: creation_modifier IDENTIFIER init_spec call_arguments  { $$=new CreationCall(@1,$1,$2,$3,$4); }

creation_modifier:   '!' '!'              { $$=NULL; }
           |         '!' class_type '!'   { $$=$2;   }
           ;

init_spec:     '.' IDENTIFIER  { $$=$2; }
       ;
call_arguments:  /* empty */              { $$=NULL; }
            |   '(' ')'                   { $$=CREATE_LIST(@1,AbstractNode); }
            |   '(' expression_list ')'   { $$=$2;   }
            ;

basic_loop: FROM compound UNTIL nloe expression nloe LOOP compound END_DECL  { $$=new FromLoopNode(@1,$2,$5,$8); }

